package com.guangfeng.yql.security;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.guangfeng.yql.comm.util.HttpContextUtils;
import com.guangfeng.yql.comm.util.StringUtils;
import com.guangfeng.yql.comm.util.TokenUtils;
import com.guangfeng.yql.security.config.TokenConfig;
import com.guangfeng.yql.redis.util.RedisCacheUtil;
import com.guangfeng.yql.security.bean.LoginUser;
import com.guangfeng.yql.security.constant.Constant;
import com.guangfeng.yql.security.exception.TokenExpiredException;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class SecurityUtil {

    private static TokenConfig tokenConfig = SpringUtil.getBean(TokenConfig.class);

    public static String createToken(LoginUser user) {
        StringBuilder subject = new StringBuilder(JSONUtil.toJsonStr(user));
        String secretKey = tokenConfig.getKey();
        if (StrUtil.isNotEmpty(secretKey)) {
            subject.append(secretKey);
        }
        String tokenKey = RedisCacheUtil.getCacheObject(subject.toString());
        if (StringUtils.isNotEmpty(tokenKey)) {
            RedisCacheUtil.delete(tokenKey);
        }
        String token = TokenUtils.createToken(subject.toString());
        String key = Constant.TOKEN_PREFIX + RandomUtil.randomString(16);
        RedisCacheUtil.setCacheObject(key, token);
        RedisCacheUtil.setCacheObject(subject.toString(), key);
        setTtl(key);
        setTtl(subject.toString());
        return Base64Encoder.encode(key.getBytes(StandardCharsets.UTF_8));
    }

    public static <T> LoginUser<T> getLoginUser() {
        try {
            String authenticate = Base64Decoder.decodeStr(HttpContextUtils.getAuthenticate()).trim();
            String jwtToken = RedisCacheUtil.getCacheObject(authenticate);
            String parseJWT = TokenUtils.parseJWT(jwtToken);
            String token = parseJWT.substring(0, parseJWT.length() - tokenConfig.getKey().length());
            LoginUser<T> login = JSONUtil.toBean(token, LoginUser.class);
            Optional.ofNullable(login).orElseThrow(TokenExpiredException::new);
            refreshToken(authenticate);
            return login;
        } catch (RuntimeException e) {
            throw new TokenExpiredException();
        }

    }

    public static Long getUserId() {
        return getLoginUser().getUserId();
    }

    public static String getNickName() {
        return getLoginUser().getNickName();
    }

    public static String getPhone() {
        return getLoginUser().getPhone();
    }

    public static void refreshToken(String key) {
        setTtl(key);
    }

    private static void setTtl(String key) {
        RedisCacheUtil.expire(key, tokenConfig.getTtl() == null ? tokenConfig.getDefaultTtl() : tokenConfig.getTtl(), TimeUnit.MILLISECONDS);
    }
}
